#include "time_util.h"

#include <cstring>
#include <stdexcept>
#include <vector>
#include <chrono>

namespace Base {
namespace Utils {
namespace {
std::string FormatTmInternal(const tm& timeInfo, const char* format) {
    std::vector<char> buffer(256);
    
    #ifdef __GNUC__
    #pragma GCC diagnostic push
    #pragma GCC diagnostic ignored "-Wformat-nonliteral"
    #endif
    
    while (true) {
        size_t size = strftime(buffer.data(), buffer.size(), format, &timeInfo);
        if (size > 0) {
            #ifdef __GNUC__
            #pragma GCC diagnostic pop
            #endif
            return std::string(buffer.data(), size);
        }
        
        if (buffer.size() > 65536) {
            #ifdef __GNUC__
            #pragma GCC diagnostic pop
            #endif
            throw std::runtime_error("Time format exceeds maximum buffer size");
        }
        buffer.resize(buffer.size() * 2);
    }
}
} // namespace

int TimeUtil::timezoneOffset_ = 0;
bool TimeUtil::timezoneSet_ = false;

void TimeUtil::GetCurrentTimeStruct(struct tm& output) {
    time_t now = time(nullptr);

    if (timezoneSet_) {
        now += timezoneOffset_ * 3600;
    }

#ifdef _WIN32
    localtime_s(&output, &now);
#else
    localtime_r(&now, &output);
#endif
}

template <size_t N>
std::string TimeUtil::GetCurrentTimeString(const char (&format)[N]) {
    struct tm timeInfo;
    GetCurrentTimeStruct(timeInfo);
    return FormatTmInternal(timeInfo, format);
}

std::string TimeUtil::GetCurrentTimeString(const char* format) {
    if (!format) {
        return GetCurrentTimeString(DEFAULT_TIME_FORMAT);
    }
    
    struct tm timeInfo;
    GetCurrentTimeStruct(timeInfo);
    return FormatTmInternal(timeInfo, format);
}

std::string TimeUtil::GetCurrentTimeStringWithMilliseconds(const char* format) {
    if (!format) {
        format = DEFAULT_TIME_FORMAT;
    }
    
    // 获取当前时间和毫秒
    using namespace std::chrono;
    auto now = system_clock::now();
    auto time_t_now = system_clock::to_time_t(now);
    auto duration = now.time_since_epoch();
    auto millis = duration_cast<milliseconds>(duration) % 1000;
    
    // 应用时区偏移
    if (timezoneSet_) {
        time_t_now += timezoneOffset_ * 3600;
    }
    
    struct tm timeInfo;
#ifdef _WIN32
    localtime_s(&timeInfo, &time_t_now);
#else
    localtime_r(&time_t_now, &timeInfo);
#endif
    
    // 格式化基本时间部分
    std::string timeStr = FormatTmInternal(timeInfo, format);
    
    // 添加毫秒部分
    char millisBuffer[8];
    snprintf(millisBuffer, sizeof(millisBuffer), ".%03d", static_cast<int>(millis.count()));
    timeStr += millisBuffer;
    
    return timeStr;
}

uint64_t TimeUtil::GetCurrentMilliseconds() {
    using namespace std::chrono;
    auto duration = duration_cast<milliseconds>(
        system_clock::now().time_since_epoch()
    );
    // 显式处理有符号到无符号转换
    return static_cast<uint64_t>(duration.count());
}

uint64_t TimeUtil::GetCurrentMicroseconds() {
    using namespace std::chrono;
    auto duration = duration_cast<microseconds>(
        system_clock::now().time_since_epoch()
    );
    return static_cast<uint64_t>(duration.count());
}

uint64_t TimeUtil::GetCurrentNanoseconds() {
    using namespace std::chrono;
    auto duration = duration_cast<nanoseconds>(
        system_clock::now().time_since_epoch()
    );
    return static_cast<uint64_t>(duration.count());
}

template <size_t N>
std::string TimeUtil::FormatTime(time_t t, const char (&format)[N]) {
    if (timezoneSet_) {
        t += timezoneOffset_ * 3600;
    }
    struct tm timeInfo;
#ifdef _WIN32
    localtime_s(&timeInfo, &t);
#else
    localtime_r(&t, &timeInfo);
#endif
    return FormatTmInternal(timeInfo, format);
}

std::string TimeUtil::FormatTime(time_t t, const char* format) {
    if (!format) {
        return FormatTime(t, DEFAULT_TIME_FORMAT);
    }
    
    if (timezoneSet_) {
        t += timezoneOffset_ * 3600;
    }
    struct tm timeInfo;
#ifdef _WIN32
    localtime_s(&timeInfo, &t);
#else
    localtime_r(&t, &timeInfo);
#endif
    return FormatTmInternal(timeInfo, format);
}

void TimeUtil::SetTimezone(int offset) {
    if (offset < -12 || offset > 14) {
        throw std::invalid_argument("Invalid timezone offset");
    }
    timezoneOffset_ = offset;
    timezoneSet_ = true;
}

int TimeUtil::GetTimezoneOffset() {
    return timezoneOffset_;
}

template std::string TimeUtil::GetCurrentTimeString<23>(const char (&)[23]);
template std::string TimeUtil::FormatTime<23>(time_t, const char (&)[23]);
} // namespace Utils
} // namespace Base